# -*- coding: utf-8 -*-
import os
import sys
import ezdxf
import click
from pathlib import Path
import shutil
from ezdxf.upright import upright_all  # 新增：导入法向量修复函数

# 完整的编码解决方案
def setup_console_encoding():
    """设置控制台编码以正确显示中文"""
    if sys.platform.startswith('win'):
        try:
            # 设置环境变量
            os.environ['PYTHONIOENCODING'] = 'utf-8'
            
            # 重新配置标准输出流
            import codecs
            import locale
            
            # 获取系统默认编码
            encoding = locale.getpreferredencoding()
            if encoding.lower() not in ['utf-8', 'utf8']:
                # 强制使用UTF-8
                sys.stdout.reconfigure(encoding='utf-8', errors='replace')
                sys.stderr.reconfigure(encoding='utf-8', errors='replace')
            
        except Exception as e:
            # 如果重新配置失败，使用备用方案
            try:
                sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer, errors='replace')
                sys.stderr = codecs.getwriter('utf-8')(sys.stderr.buffer, errors='replace')
            except:
                # 最后的备用方案：使用gbk编码（Windows中文系统默认）
                try:
                    sys.stdout = codecs.getwriter('gbk')(sys.stdout.buffer, errors='replace')
                    sys.stderr = codecs.getwriter('gbk')(sys.stderr.buffer, errors='replace')
                except:
                    pass  # 如果都失败了，使用默认编码

# 初始化编码设置
setup_console_encoding()

def mirror_dxf_file(input_path, output_path):
    """Mirror a DXF file horizontally (left-right flip)."""
    try:
        click.echo(f"正在读取DXF文件: {input_path}")
        click.echo(f"Reading DXF file: {input_path}")
        
        # 读取DXF文件
        doc = ezdxf.readfile(input_path)
        msp = doc.modelspace()
        
        click.echo("正在应用左右镜像变换...")
        click.echo("Applying left-right mirror transformation...")
        
        # 创建镜像变换矩阵 (X轴镜像: x坐标取反，y和z坐标保持不变)
        mirror_matrix = ezdxf.math.Matrix44.scale(-1, 1, 1)
        
        # 对所有实体应用镜像变换，但特殊处理文字实体
        entity_count = 0
        text_count = 0
        
        for entity in msp:
            if hasattr(entity, 'transform'):
                # 检查是否为文字类实体
                if entity.dxftype() in ['TEXT', 'MTEXT', 'ATTRIB', 'ATTDEF']:
                    # 对文字实体特殊处理：只镜像位置，不镜像文字内容
                    handle_text_entity(entity, mirror_matrix)
                    text_count += 1
                else:
                    # 对其他实体正常应用镜像变换
                    entity.transform(mirror_matrix)
                
                entity_count += 1
        
        # 新增：修复Z轴法向量，避免镜像后实体显示异常（ezdxf官方推荐）
        click.echo("正在修复实体法向量...")
        click.echo("Fixing entity normal vectors...")
        upright_all(msp)
        
        click.echo(f"已处理 {entity_count} 个图形实体 (其中 {text_count} 个文字实体)")
        click.echo(f"Processed {entity_count} graphic entities ({text_count} text entities)")
        
        # 确保输出目录存在
        output_path.parent.mkdir(parents=True, exist_ok=True)
        
        # 保存镜像后的文件
        click.echo(f"正在保存镜像文件: {output_path}")
        click.echo(f"Saving mirrored file: {output_path}")
        doc.saveas(str(output_path))
        
        click.echo("✅ DXF文件镜像完成!")
        click.echo("✅ DXF file mirroring completed!")
        return True
        
    except FileNotFoundError:
        click.echo(f"❌ 错误: 找不到输入文件 {input_path}", err=True)
        click.echo(f"❌ Error: Input file {input_path} not found", err=True)
        return False
    except ezdxf.DXFStructureError as e:
        click.echo(f"❌ DXF文件结构错误: {e}", err=True)
        click.echo(f"❌ DXF file structure error: {e}", err=True)
        return False
    except Exception as e:
        click.echo(f"❌ 处理文件时发生错误: {e}", err=True)
        click.echo(f"❌ Error processing file: {e}", err=True)
        return False

def handle_text_entity(entity, mirror_matrix):
    """特殊处理文字实体：只镜像位置，保持文字可读性"""
    try:
        # 获取文字实体的插入点/位置
        if hasattr(entity.dxf, 'insert'):
            # TEXT 和 MTEXT 使用 insert 属性
            original_pos = entity.dxf.insert
            # 只对位置应用镜像变换
            new_pos = mirror_matrix.transform(original_pos)
            entity.dxf.insert = new_pos
            
            # 调整文字对齐方式以保持视觉效果
            if hasattr(entity.dxf, 'halign'):
                # 水平对齐方式镜像: 左对齐<->右对齐
                if entity.dxf.halign == 0:  # 左对齐
                    entity.dxf.halign = 2   # 改为右对齐
                elif entity.dxf.halign == 2:  # 右对齐
                    entity.dxf.halign = 0    # 改为左对齐
                # 居中对齐(1)保持不变
                
        elif hasattr(entity.dxf, 'location'):
            # ATTRIB 和 ATTDEF 可能使用 location 属性
            original_pos = entity.dxf.location
            new_pos = mirror_matrix.transform(original_pos)
            entity.dxf.location = new_pos
            
    except Exception as e:
        # 如果特殊处理失败，回退到普通变换
        click.echo(f"警告: 文字实体特殊处理失败，使用普通变换: {e}", err=True)
        entity.transform(mirror_matrix)

def transform_filename(original_name):
    """根据README规则转换文件名"""
    # 移除 ~待镜像 标记
    name = original_name.replace("~待镜像", "")
    
    # 处理方向性字符
    if "左" in name:
        name = name.replace("左", "右")
    elif "右" in name:
        name = name.replace("右", "左")
    else:
        # 如果没有方向性字符，添加 ~反 后缀
        name_parts = name.rsplit('.', 1)
        if len(name_parts) == 2:
            name = f"{name_parts[0]}~反.{name_parts[1]}"
        else:
            name = f"{name}~反"
    
    return name

@click.command()
@click.argument('input_folder', type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path))
@click.option('--output-folder', '-o', type=click.Path(path_type=Path), 
              help='输出文件夹路径（默认为输入文件夹_out）/ Output folder path (default: input_folder_out)')
def main(input_folder, output_folder):
    """DXF自动左右镜像翻转工具
    
    自动处理指定文件夹中所有包含 '~待镜像' 的DXF文件，进行左右镜像翻转并重命名。
    新增：修复Z轴法向量，避免镜像后实体显示异常。
    
    DXF Automatic Left-Right Mirror Tool
    
    Automatically processes all DXF files containing '~待镜像' in the specified folder,
    performs left-right mirroring and renames them.
    New: Fix Z-axis normal vectors to avoid display anomalies after mirroring.
    """
    
    click.echo("="*60)
    click.echo("DXF自动左右镜像翻转工具（新增法向量修复）")
    click.echo("DXF Automatic Left-Right Mirror Tool (with normal vector fix)")
    click.echo("="*60)
    click.echo()
    
    # 设置输出文件夹
    if output_folder is None:
        output_folder = Path(f"{input_folder}_out")
    
    click.echo(f"输入文件夹: {input_folder}")
    click.echo(f"Input folder: {input_folder}")
    click.echo(f"输出文件夹: {output_folder}")
    click.echo(f"Output folder: {output_folder}")
    click.echo()
    
    # 创建输出文件夹
    output_folder.mkdir(parents=True, exist_ok=True)
    
    # 搜索包含 "~待镜像" 的DXF文件
    pattern = "*~待镜像*.dxf"
    dxf_files = list(input_folder.glob(pattern))
    
    if not dxf_files:
        click.echo(f"❌ 未找到包含 '~待镜像' 的DXF文件")
        click.echo(f"❌ No DXF files containing '~待镜像' found")
        click.echo(f"搜索模式: {pattern}")
        click.echo(f"Search pattern: {pattern}")
        return
    
    click.echo(f"找到 {len(dxf_files)} 个待处理文件:")
    click.echo(f"Found {len(dxf_files)} files to process:")
    for file in dxf_files:
        click.echo(f"  - {file.name}")
    click.echo()
    
    # 处理每个文件
    success_count = 0
    deleted_count = 0
    total_count = len(dxf_files)
    
    for i, input_file in enumerate(dxf_files, 1):
        click.echo(f"[{i}/{total_count}] 处理文件: {input_file.name}")
        click.echo(f"[{i}/{total_count}] Processing file: {input_file.name}")
        
        # 生成输出文件名
        output_filename = transform_filename(input_file.name)
        output_file = output_folder / output_filename
        
        click.echo(f"输出文件名: {output_filename}")
        click.echo(f"Output filename: {output_filename}")
        
        # 执行镜像操作
        if mirror_dxf_file(input_file, output_file):
            success_count += 1
            click.echo("✅ 镜像处理成功!")
            click.echo("✅ Mirroring successful!")
            
            # 镜像成功后删除原文件
            try:
                click.echo(f"正在删除原文件: {input_file.name}")
                click.echo(f"Deleting original file: {input_file.name}")
                input_file.unlink()  # 删除文件
                deleted_count += 1
                click.echo("🗑️ 原文件已删除")
                click.echo("🗑️ Original file deleted")
            except Exception as e:
                click.echo(f"⚠️ 警告: 无法删除原文件 {input_file.name}: {e}", err=True)
                click.echo(f"⚠️ Warning: Failed to delete original file {input_file.name}: {e}", err=True)
        else:
            click.echo("❌ 镜像处理失败!")
            click.echo("❌ Mirroring failed!")
            click.echo("⚠️ 保留原文件 (处理失败)")
            click.echo("⚠️ Original file preserved (processing failed)")
        
        click.echo("-" * 40)
    
    # 显示处理结果
    click.echo()
    click.echo("="*60)
    click.echo("处理完成 / Processing completed")
    click.echo(f"成功镜像: {success_count}/{total_count} 个文件")
    click.echo(f"Successfully mirrored: {success_count}/{total_count} files")
    click.echo(f"已删除原文件: {deleted_count}/{success_count} 个")
    click.echo(f"Original files deleted: {deleted_count}/{success_count}")
    
    if success_count == total_count and deleted_count == success_count:
        click.echo("🎉 所有文件处理成功，原文件已清理!")
        click.echo("🎉 All files processed successfully, original files cleaned up!")
    elif success_count == total_count:
        click.echo("✅ 所有文件镜像成功，但部分原文件未能删除")
        click.echo("✅ All files mirrored successfully, but some original files could not be deleted")
    elif success_count > 0:
        click.echo("⚠️ 部分文件处理成功")
        click.echo("⚠️ Partially successful")
    else:
        click.echo("💥 所有文件处理失败")
        click.echo("💥 All files failed to process")
    
    click.echo("="*60)

if __name__ == "__main__":
    main()